<script setup lang="ts">
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import * as echarts from 'echarts'
import 'echarts-gl'
import { getPie3D } from './pie3DOption.js'

const props = defineProps({
  option: {
    type: Object,
    default: () => ({})
  },
  data: {
    type: Array,
    default: () => []
  },
  autoAction: {
    type: Boolean,
    default: false
  }
})

const chartDomRef = ref()
let chartInstance = null
let selectedIndex = null
let hoveredIndex = null

const generateOption = (option, data) => {
  const {
    type,
    color,
    lableShow,
    labelColor,
    innerRadius,
    outerRadius,
    legendTextStyleColor,
    datasetDimensions,
    datasetSourceProduct
  } = option

  const opt: any = {
    color: color ?? [
      'hsla(240, 100%, 67%, 1)',
      'hsla(120, 100%, 67%, 1)',
      'hsla(60, 100%, 67%, 1)',
      'hsla(30, 100%, 67%, 1)'
    ],
    title: {
      show: false
    },
    tooltip: {
      trigger: 'item',
      textStyle: {
        color: 'var(--ec-text-color)'
      },
      backgroundColor: 'var(--ec-background-color)',
      borderColor: 'var(--ec-border-color)',
      formatter: (params) =>
        `${params.data[datasetSourceProduct]} ${params.data[datasetDimensions[0]]}<br />${params.percent}%`
    },
    dataset: {
      dimensions: ['product', ...datasetDimensions],
      source: data.map((data: any) => {
        data.product = data[datasetSourceProduct]
        return data
      })
    },
    legend: {
      textStyle: {
        color: legendTextStyleColor ?? '#aaa'
      },
      itemWidth: 20,
      itemHeight: 10,
      icon: 'roundRect'
    },
    grid: {
      left: '3%',
      right: '4%',
      bottom: '3%',
      containLabel: true
    },
    series: []
  }

  opt.series = [
    {
      type: 'pie',
      label: {
        show: lableShow,
        color: labelColor,
        textBorderColor: 'transparent',
        textBorderWidth: 0
      },
      radius: [innerRadius, outerRadius]
    }
  ]

  if (type == 'pie') return opt
  else if (type == 'pie3D') {
    const pieData = data.map((v, i) => {
      return {
        name: v[datasetSourceProduct],
        value: v[datasetDimensions[0]],
        itemStyle: {
          color: color[i],
          opacity: 1
        },
        selected: v.selected ?? false,
        hovered: v.hovered ?? false
      }
    })

    const opt3D = getPie3D(pieData, innerRadius, outerRadius, lableShow)

    opt3D.legend = opt.legend
    opt3D.legend.selectedMode = false

    return opt3D
  }

  return opt
}

const onClick = (params) => {
  if (props.option.type !== 'pie3D') return

  if (selectedIndex === params.seriesIndex) selectedIndex = null
  else selectedIndex = params.seriesIndex

  const data = props.data.map((element: any, index) => {
    return {
      ...element,
      selected: selectedIndex == index
    }
  })

  chartInstance.setOption(generateOption(props.option, data))
}

const onMouseMove = (params) => {
  if (props.option.type !== 'pie3D') return
  if (hoveredIndex === params.seriesIndex) return

  hoveredIndex = params.seriesIndex

  const data = props.data.map((element: any, index) => {
    return {
      ...element,
      selected: selectedIndex == index,
      hovered: hoveredIndex == index
    }
  })

  chartInstance.setOption(generateOption(props.option, data))
}

watch(
  props,
  () => {
    if (chartInstance) {
      chartInstance.clear()
      chartInstance.setOption(generateOption(props.option, props.data), { notMerge: true })
    }
  },
  { deep: true }
)
// 轮流选择
let currentIndex = -1
let intervalAction = null
let actionDelay = 1000
let actionable = ref(true)

const action = function () {
  if (!actionable.value || !chartInstance) return

  let dataLen = props.data.length

  chartInstance.dispatchAction({
    type: 'downplay',
    seriesIndex: 0,
    dataIndex: currentIndex
  })

  const index = (currentIndex + 1) % dataLen
  currentIndex = Number.isNaN(index) ? -1 : index

  chartInstance.dispatchAction({
    type: 'highlight',
    seriesIndex: 0,
    dataIndex: currentIndex
  })
  chartInstance.dispatchAction({
    type: 'showTip',
    seriesIndex: 0,
    dataIndex: currentIndex
  })
}

watch(
  () => props.autoAction,
  (newVal) => {
    if (intervalAction) clearInterval(intervalAction)

    if (newVal) intervalAction = setInterval(action, actionDelay)
  },
  {
    immediate: true
  }
)
// 初始化
const initChart = () => {
  nextTick(() => {
    chartInstance = echarts.init(chartDomRef.value)
    chartInstance.setOption(generateOption(props.option, props.data))

    chartInstance.on('click', onClick)
    chartInstance.on('mousemove', onMouseMove)
  })
}

let resizeObserver
const chartResizeObserver = () => {
  resizeObserver = new window.ResizeObserver((entries) => chartInstance?.resize())
  resizeObserver.observe(chartDomRef.value)
}

onMounted(() => {
  initChart()
  chartResizeObserver()
})

onUnmounted(() => {
  chartInstance?.dispose()
  chartInstance = null
  if (resizeObserver) resizeObserver.disconnect()
})
</script>

<template>
  <div ref="chartDomRef" :style="{ width: '100%', height: '100%' }" @mouseover="actionable = false"
    @mouseout="actionable = true"></div>
</template>

<style scoped></style>
